import pandas as pd
import re
from datetime import datetime

class DataRules:
    """数据处理通用规则库（公共模块）"""
    
    @staticmethod
    def convert_scientific_notation(df: pd.DataFrame, fields: list, result_col: str = "检查结果") -> pd.DataFrame:
        """
        处理科学计数法转换为文本格式
        
        参数:
            df: 待处理的DataFrame
            fields: 需要处理的字段列表
            result_col: 检查结果记录列名
        """
        for field in fields:
            if field in df.columns:
                # 判断是否为纯数字
                is_pure_digit = df[field].astype(str).str.fullmatch(r'^\d+$', na=False)
                if is_pure_digit.any():
                    # 转换为字符串并处理小数点
                    df.loc[is_pure_digit, field] = df.loc[is_pure_digit, field].astype(str).str.replace(r'\.0$', '', regex=True)
                    
                    # 处理科学计数法
                    scientific_mask = is_pure_digit & df[field].astype(str).str.contains(r'^[+-]?\d+\.?\d*[eE][+-]?\d+$', na=False)
                    if scientific_mask.any():
                        df.loc[scientific_mask, field] = df.loc[scientific_mask, field].apply(
                            lambda x: f"{int(float(x)):d}" if '.' in x else f"{int(float(x)):d}"
                        )
                        df.loc[scientific_mask, result_col] += f'{field}已从科学计数法转换为文本; '
        return df
    
    @staticmethod
    def validate_price_fields(df: pd.DataFrame, fields: list = ['总部售价', '门店售价'], result_col: str = "检查结果") -> pd.DataFrame:
        """
        验证售价字段，将0或空值改为1
        
        参数:
            df: 待处理的DataFrame
            fields: 价格字段列表
            result_col: 检查结果记录列名
        """
        for field in fields:
            if field in df.columns:
                # 检查空值或0值
                mask = df[field].isna() | (df[field].astype(str).str.strip() == '0') | (df[field].astype(str).str.strip() == '')
                if mask.any():
                    df.loc[mask, field] = 1
                    df.loc[mask, result_col] += f'{field}为0或空已调整为1; '
        return df
    
    @staticmethod
    def fill_empty_manufacturer(df: pd.DataFrame, field: str = "厂家", fill_value: str = "无", result_col: str = "检查结果") -> pd.DataFrame:
        """
        填充空的厂家字段
        
        参数:
            df: 待处理的DataFrame
            field: 厂家字段名
            fill_value: 填充值
            result_col: 检查结果记录列名
        """
        if field in df.columns:
            mask = df[field].isna() | (df[field].str.strip() == "")
            if mask.any():
                df.loc[mask, field] = fill_value
                df.loc[mask, result_col] += f'{field}不能为空已填充为"{fill_value}"; '
        return df
    
    @staticmethod
    def validate_drug_code_length(df: pd.DataFrame, field: str = "药品编码", invalid_length: int = 14, result_col: str = "检查结果") -> pd.DataFrame:
        """
        检查药品编码长度是否为无效值
        
        参数:
            df: 待处理的DataFrame
            field: 药品编码字段名
            invalid_length: 无效长度值
            result_col: 检查结果记录列名
        """
        if field in df.columns:
            is_pure_digit = df[field].astype(str).str.fullmatch(r'^\d+$', na=False)
            if is_pure_digit.any():
                code_length = df.loc[is_pure_digit, field].str.len()
                mask = is_pure_digit & (code_length == invalid_length)
                if mask.any():
                    df.loc[mask, result_col] += f'{field}位数不能等于{invalid_length}; '
        return df
    
    @staticmethod
    def clean_drug_name(df: pd.DataFrame, field: str = "药品", result_col: str = "检查结果") -> pd.DataFrame:
        """
        清理药品名称前的特殊字符
        
        参数:
            df: 待处理的DataFrame
            field: 药品名称字段名
            result_col: 检查结果记录列名
        """
        if field in df.columns:
            original_name = df[field].copy()
            df[field] = df[field].str.lstrip('*')
            mask = original_name != df[field]
            if mask.any():
                df.loc[mask, result_col] += f'{field}名称前不能包含特殊字符已去除*; '
        return df
    
    @staticmethod
    def process_approval_number(df: pd.DataFrame, approval_field: str = "国药准字", type_field: str = "类型", result_col: str = "检查结果") -> pd.DataFrame:
        """
        根据国药准字处理类型字段
        
        参数:
            df: 待处理的DataFrame
            approval_field: 国药准字字段名
            type_field: 类型字段名
            result_col: 检查结果记录列名
        """
        if approval_field in df.columns and type_field in df.columns:
            original_type = df[type_field].copy()
            
            # 定义各类批准文号对应的类型
            mask_zy = df[approval_field].str.contains('国药准字', na=False)
            mask_gsjz = df[approval_field].str.contains('国食健字', na=False)
            mask_zhuang = df[approval_field].str.contains('妆', na=False)
            mask_xc = df[approval_field].str.contains('械', na=False)
            mask_xs = df[approval_field].str.contains('消', na=False)
            
            # 应用类型转换规则
            df.loc[mask_zy & (df[type_field] != '西药中成药'), type_field] = '西药中成药'
            df.loc[mask_gsjz & (df[type_field] != '其他商品'), type_field] = '其他商品'
            df.loc[mask_zhuang & (df[type_field] != '其他商品'), type_field] = '其他商品'
            df.loc[mask_xc & (df[type_field] != '耗材'), type_field] = '耗材'
            df.loc[mask_xs & (df[type_field] != '耗材'), type_field] = '耗材'
            
            # 记录类型变更
            changed_zy = mask_zy & (original_type != df[type_field])
            changed_gsjz = mask_gsjz & (original_type != df[type_field])
            changed_zhuang = mask_zhuang & (original_type != df[type_field])
            changed_xc = mask_xc & (original_type != df[type_field])
            changed_xs = mask_xs & (original_type != df[type_field])
            
            df.loc[changed_zy, result_col] += '国药准字:类型设为西药中成药; '
            df.loc[changed_gsjz, result_col] += '国食健字:类型设为其他商品; '
            df.loc[changed_zhuang, result_col] += '妆:类型设为其他商品; '
            df.loc[changed_xc, result_col] += '械:类型设为耗材; '
            df.loc[changed_xs, result_col] += '消:类型设为耗材; '
        return df
    
    @staticmethod
    def check_split_unit(df: pd.DataFrame, qty_field: str = "拆零数量", unit_field: str = "单位", split_unit_field: str = "拆零单位", result_col: str = "检查结果") -> pd.DataFrame:
        """
        检查拆零单位是否与原单位相同，并在拆零数量为1时自动修正拆零单位
        
        参数:
            df: 待处理的DataFrame
            qty_field: 拆零数量字段名
            unit_field: 单位字段名
            split_unit_field: 拆零单位字段名
            result_col: 检查结果记录列名
        """
        if all(col in df.columns for col in [qty_field, unit_field, split_unit_field]):
            for idx, row in df.iterrows():
                try:
                    # 获取拆零数量、单位和拆零单位的值
                    cl = int(row[qty_field]) if pd.notna(row[qty_field]) else 0
                    unit = str(row[unit_field]).strip()
                    cl_unit = str(row[split_unit_field]).strip()
                    
                    # 拆零数量>1时，单位与拆零单位应不同
                    if cl > 1 and unit == cl_unit:
                        df.at[idx, result_col] += f"单位({unit})与拆零单位({cl_unit})应不同; "
                    # 拆零数量=1时，单位与拆零单位应相同，不同则自动修正
                    elif cl == 1 and unit != cl_unit:
                        # 将拆零单位修改为单位的值
                        df.at[idx, split_unit_field] = unit
                        df.at[idx, result_col] += f"拆零数量为1，已将拆零单位从{cl_unit}修改为{unit}; "
                except (ValueError, TypeError):
                    # 处理非数字的拆零数量或其他类型错误
                    pass
        return df
    
    @staticmethod
    def format_date_fields(df: pd.DataFrame, fields: list = ["最近生产日期", "最近效期"], result_col: str = "检查结果", target_format: str = "%Y-%m-%d") -> pd.DataFrame:
        """
        将日期字段格式化为指定格式，默认YYYY-MM-DD格式
        
        参数:
            df: 待处理的DataFrame
            fields: 需要格式化的日期字段列表
            result_col: 检查结果记录列名
            target_format: 目标日期格式，默认YYYY-MM-DD
        """
        # 支持的输入日期格式列表
        date_formats = [
            "%Y-%m-%d", "%Y/%m/%d", "%Y年%m月%d日",  # 年-月-日格式
            "%m-%d-%Y", "%m/%d/%Y", "%m月%d日%Y年",  # 月-日-年格式
            "%d-%m-%Y", "%d/%m/%Y", "%d月%m月%Y年",  # 日-月-年格式
            "%Y%m%d", "%y%m%d",  # 纯数字格式（8位或6位）
            "%Y-%m-%d %H:%M:%S", "%Y/%m/%d %H:%M:%S",  # 带时间的格式
            "%m-%d-%y", "%m/%d/%y", "%d-%m-%y", "%d/%m/%y"  # 两位年份格式
        ]
        
        for field in fields:
            if field in df.columns:
                for idx, value in df[field].items():
                    if pd.isna(value) or str(value).strip() in ['', 'nan']:
                        continue
                        
                    original_value = str(value).strip()
                    formatted_date = None
                    
                    # 对"最近效期"字段的YYYY/MM格式特殊处理（保持纯数字年月格式）
                    if field == "最近效期":
                        yyyymm_slash_pattern = re.fullmatch(r'^\d{4}/\d{1,2}$', original_value)
                        if yyyymm_slash_pattern:
                            year, month = original_value.split('/')
                            month = month.zfill(2)
                            formatted_date = year + month
                            if 1 <= int(month) <= 12:
                                df.at[idx, field] = formatted_date
                                df.at[idx, result_col] += f'{field}已转换为年月格式{formatted_date}; '
                                continue
                    
                    # 尝试多种格式解析日期
                    for fmt in date_formats:
                        try:
                            date_obj = datetime.strptime(original_value, fmt)
                            formatted_date = date_obj.strftime(target_format)
                            break
                        except (ValueError, TypeError):
                            continue
                            
                    # 如果直接解析失败，尝试清理特殊字符后再解析
                    if formatted_date is None:
                        cleaned_value = re.sub(r'[^\d/-]', '', original_value)
                        if cleaned_value != original_value and cleaned_value:
                            for fmt in date_formats:
                                try:
                                    date_obj = datetime.strptime(cleaned_value, fmt)
                                    formatted_date = date_obj.strftime(target_format)
                                    break
                                except (ValueError, TypeError):
                                    continue
                    
                    # 处理两位年份（6位数字）
                    if formatted_date and len(formatted_date) == 6 and re.fullmatch(r'^\d{6}$', formatted_date):
                        year = formatted_date[:2]
                        month = formatted_date[2:4]
                        day = formatted_date[4:6]
                        if 1 <= int(month) <= 12 and 1 <= int(day) <= 31:
                            formatted_date = f"20{year}-{month}-{day}"
                    
                    # 更新日期或记录错误
                    if formatted_date:
                        try:
                            datetime.strptime(formatted_date, target_format)
                            if formatted_date != original_value:
                                df.at[idx, field] = formatted_date
                                df.at[idx, result_col] += f'{field}日期已转换为{target_format}格式; '
                        except ValueError:
                            df.at[idx, result_col] += f'{field}日期无效: {formatted_date}; '
        
        return df